PIC18 USB温度計
Microchip社から無償で配布されている MCHPFSUSB(マイクロチップ・フルスピード・USB)から、文字通信(CDC)クラスの雛形ソフト USB Device - CDC - Basic Demo を改造して、目的のプログラムを作成することにする。これらのプログラムは
多くの機種に対応できるよう汎用性を持たせて作られているので、特定の用途には無駄な部分が多いので できるだけ削除して、フラッシュメモリ(ROM)の容量を軽減する。削除に手間がかかるが、最初から新しくプログラムを作るよりは効率的なので、このようにした。 ただし、自前で作ったプログラムに比べ、プログラムのサイズがかなり大きくなる問題がある。
(1) USB Device - CDC - Basic Demo の整備: ( 注) MCHPFSUSB 2010_02_09 版の r14K50eb から CDC-BASIC-DEMO
を使用、最新バージョンではプログラムの変更要)
電源をパソコンのUSBから取る、コンパクトな USB温度計を作製する。
この USB通信で用いているのは、パソコンからの受信(キーボード入力により制御)、パソコンへの送信(温度データ出力表示)であり、それぞれ
関数 getsUSBUSART、 putUSBUSART などを用いた。 特に、USB通信は、個別にデータを送・受信するのではなく、64バイト(あるいはそれ以上)以内のバイトサイズのデータをまとめて扱う。
そのため、シリアル通信やLCDの表示のように 個別の関数を続けて使用することはできず、あらかじめ 送・受信バッファにすべてのデータを組み込む必要がある。 また、パソコン側から見て、USB接続しているこれらのデータはシリアルとして扱われる。(仮想シリアルCOM3ポートが作られている(前節参照))
まず、下図の手順により、(無駄な部分もあるが、)プロジェクトのフォルダ、ディレクトリ、#include
などの整備を行なう。 無事、ビルドができたら、次に、USB Device - CDC - Basic
の説明文や、他の機種の記述の部分、また、機能と関係の無い LEDを光らせる関数やボタンの関数などの削除を行なう。(ベクトル・割込み設定の部分は残す)
削除毎にビルドし、エラーが出ないことを確認する。
(2) 温度計ハードの作製:
今回は、リファレンスICによる外部参照電圧を作り 精度を上げるようにした。また、温度センサの後にオペアンプを入れ、増幅と共に 入力電圧を調整できるようにした。
LM35DZは 価格の割りに良くできたICで、0−100℃の範囲で、高精度(±1℃)の 摂氏温度に比例する電圧を、しかも直示できるようにmV単位で出力する。( ex)50℃: 500mV) この出力電圧を、入力段のオペアンプと PIC内の演算により トータル 30倍に増幅し、ADコンバーターの参照電圧を 3.072Vとすると、出力結果を演算して5桁の作業領域のバッファに入れた値 buf[ i ] ( i = 0〜4) のうち、 buf[1] 〜 buf[3] の数字を並べて ○○.○(℃)として表示することができる。 99.9℃まで表示できるように、オペアンプのゲインは 約3倍、PIC内の倍率は 10倍 (v = v*10)とした。
そのために、可変リファレンスIC(TL431)から出力される参照電圧が、 30
× 1024 = 30720 (10ビットADコンバーターなので 210 = 1024個に参照電圧を分割する) すなわち、 VREF+ = 3.072V となるように 10kΩVR(多回転)で調整する。
オペアンプのゲイン(50kΩVR(多回転))は、実際に温度を測定しながら最後に調整する。(* もっと直線性の良い回路で作製し、また、さらに精度の高いリファレンスICも必要に応じて用いていきたい。)
(3) プログラムの作成:
プログラムで特に作製する部分は、main と processIO と 初期化の部分である。
12MHz外部振動子(レゾネータ)による発振を用いる。 CPUデバイダの値は1/1(NOCLKDIV、 CLKDIV2では
1/2、4では1/4)とし、48MHz → 12MHzの動作クロックとなる。Delay はこれにあわせて設定。 USBは 48MHz発振でパソコンと通信できる。
(↓1列目)
割込み関数部はDEMOプログラムに設定済みで、USBの ポーリングモード設定(USBDeviceTasks();)がすでに高優先割り込みの中に入っている。そのため、なぜか、タイマーなどの割込みが 低優先割込みにさえも 一切使えず(使うとUSB通信に変調をきたして、パソコンが受け付けない)、やむなく
時間設定は Delay で行うしかなかった。 (↓ 2列目)
OpenADCの2項目の設定(ADコンバーターの参照電圧)で、VREF+(外部参照電圧・+・ポジ)と GNDとの間の電圧をとった。 また、動作周波数にあわせて、ADC_FOSCを16に変更した。
(main関数、↓3列目)
main関数から飛ぶ 関数ProcessIOで、CDCクラスの送受信を行なう。 (↓4列目)
・ getsUSBUSART(受信バッファ名(USB_OUT_Buffer)、文字数(64)) ・・・ (64バイトの)文字データをパソコンから受信し、受信バッファ(USB_OUT_Buffer)に格納し、含まれているバイト数を読み込む
・ mUSBUSARTIsTxTrfReady() ・・・ これが1ならば USB送信可能、送信のとき必ず if 文でチェックする(ポーリング処理なので While文は不可)
・ putUSBUSART(送信バッファ名(USB_IN_Buffer)、文字数(5)) ・・・ 送信バッファ(USB_IN_Buffer)に格納されている (5バイトの)文字データを
送信にセットする(* 書き込むバイト数が64バイトを超えている場合、64バイト単位で複数回に分けて送信する) また、
・ putrsUSBUSART(”文字列”) ・・・ プログラム(ROM)に書かれている文字列データをそのまま送る
・ putsUSBUSART(”文字列”) ・・・ ユーザーデータ(RAM)にある文字列データをそのまま送る
・ CDCTxService() ・・・ 実際に送信を行なう
送信のときの使い方は、いずれも、
if(mUSBUSARTIsTxTrfReady()){
putUSBUSART(buffer, WriteSize);
}
CDCTxService();
のように前後で挟む書式になる。送る文字数を間違えると バッファのゴミが表示されるので注意。
バッファに入る文字データの書き方は、0x××、の他に、 '(数字・アルファベト)' でも良い。( ex) switch文の case '1': ) switch文は、 switch - case: (〜の場合)-break, case: - break, ・・・ default:(その他の場合)
- break の形で、いくつもあるジョブを場合分けする分岐命令に用いられる。
● ソース(main.cのみ): ● lib_adc.h
(4) 動作チェック と 問題点:
このプログラムで動かしてみたところ、USBケーブルを差し込むと、LCDに温度表示が現われる。
USBケーブルが差し込まれている状態で、TeraTerm などのシリアル受信ソフトを起動すると、パソコンのキーボードの
Enterキー (パソコンから受信したキーコード: 0x0A)を押すたびに、10秒間隔で 温度が縦1列に表示され続け、また、表示の更新が停止する。
消費電流は10mA前後で、USBからの+5V電源容量は最大100mA(パソコンによっては500mA)なので、充分余裕がある。(電源系統のショートには要注意)
USB Device - CDC - Basic Demo を改造して用いる際の問題点は、2つあり、
1つ目は、リンクが複雑なままのプログラム使用で プログラムのサイズが大きくなることである。 hex ファイルのファイルサイズを確認したところ、25kバイトにもなり、さらに2個以上のADコンバーターを動かすと、ROMへの書き込みはできても、RAMの容量がオーバーして動作が止まってしまうことがあった。(hex
ファイルは、LCDのみ使用の別プログラムで 6−8kバイト、LCD無しのUSB使用で
20kバイト) USB内蔵マイコンとして改造プログラムで使うには、同様に使えて
容量が大きい、もう1ランク上の PIC18F2550 等を用いるべきと思われる。
因みに、使用したMPLAB C18は、最適化の期限が過ぎている。
2つ目は、USB Device - CDC - Basic Demo には、USBのポーリングやタスク命令が
ソースプログラムの高優先割り込みに初めから組み込まれているため、このままでは
タイマー機能も、割り込み機能もほとんど使えないことである。 (特に、タイマー1との相性が悪い。ベクタを 0x08、0x18 以外に設定しても同じ) 同じようなプログラムで
タイマー0(16ビット)の割込みを低優先で入れている成功例もあるので、タイマを全く使用しないか、あるいは、リンクしている
USB関数群の通信処理部分の前後に割り込みを禁止・再開する記述を追加する必要があると思われる。
§ デジタルからアナログへ ・・・ アナログ放送は終了したけれど。。
マイコンの分野で”アナログ”といえば、ADコンバーター入力や コンパレータ入力のことを言いますが、電子工学一般では、オーディオ、高周波、オペアンプなどを アナログ回路と呼びます。
マイコンでは、細かく変化する多くの信号でサイン波を表現したり、ADコンバータで電圧レベルを細かく区切るなど、デジタルで”擬似的なアナログ信号”を作るのが一般的です。
さて、論理学・数学的には、デジタル、アナログとはどういうことを意味するのでしょう? まずは、振動方向が
1 か 0 (あるいは、+1 か −1)しかない、デジタルの世界を考えましょう。
ゲーデルの不完全性定理は、自然数論を含む公理系において、「その公理系が無矛盾ならば、その公理系で 証明も反証もできない命題が存在する」、というものです。それは、自然数を扱い、しかも、代入可能な論理系であれば、論理学、数学に限らず、(階層構造を持つ)言語や、デジタル回路、コンピューターのプログラム(関数)にも成り立ちます。
デジタル回路では、たとえば NOTゲートを奇数個つなげて 最後のゲート出力を初めのゲート入力に帰還すれば、全体が”矛盾”に陥って、発振します。これは 回路が 「負帰還」の状態になっているからです。(TTL ICの
NOTgate(74LS04)で実験したところ、11個つなげて 10数MHzで発振)
プログラムでは、「無限ループ」がよく知られています。 C言語では、 メインプログラムで while(1) を1箇所だけ入れて、ほとんどすべてのプログラムに用いられますが、これは、マイコンの設定や初期化の後、 ”電源を切るまで、while(1){ } の内容を 無限に繰り返す”、という論理構造です。 プログラムのどこかで、これとは別の無限ループに陥ると
すべての動作が止まってしまい大変困りますが、電源を切るまで 装置としてある一定の動作を繰り返し行なうためには、通常、一つのプログラムに1個だけ用いられます。
割込み関数や 他の関数、ヘッダファイルへ飛ぶことがあっても 再びそこに戻るので、基本構造は同じです。
言語 | 数学 | プログラム | デジタル回路 | |
担体 | 階層構造をもつ言語 | 自然数を含む帰納的な関数 | アルゴリズム | NAND回路の組合せ |
方法 | 自己・相互を否定的に言及 | それ自身のゲーデル数をもとの式に代入 | ジャンプ・ループ | 負帰還回路 |
結果 | パラドックス(矛盾) | 不完全性(証明も反証もできない) | 無限ループ | 不定状態・発振 |
では、アナログ回路では、この「矛盾」とは どのような形態を持っているのでしょうか?
デジタルでは、+1 と −1 の2つの状態のみが許されましたが、アナログでは
その中間の値 eiθ が存在します。(+1 と −1 の中間の値は 0 ではない!) 矛盾して、発振した状態が、きれいな正弦波のような形態になります。 デジタルは、このアナログの 特殊な状態(θ = π+2nπ、または、
−π+2nπ、 n = 0、±1、±2、・・・)の一つです。
電磁気学では、虚数単位 i の導入は便宜的なものですが、量子力学では 本質的に、物理量が複素数となっています。 驚くべきことに、自然の本質は 「複素数」です。
この eiθ の特殊な場合、オイラーの恒等式として知られる eiπ = −1 は、数学上 最もエレガントな式といわれています。 それは、全く独立して成立した 幾何学、代数学、解析学 という 数学の3大分野における、それぞれの 数学定数 π、 i 、 e が、この式において 1つに合体しているからです。
このように、思索(=数学)においても、自然(=量子力学)においても、 3つの最も根本的な要素が 1つに合体、すなわち、「三位一体」になっています。
思索も 自然も、 天地万物を創造した神 が、「三位一体の神」、すなわち、「キリスト」であることを あかししています。
(参考) → コンピューターと 神、 不完全性定理の証明、 神の愛の奥義